package com.nineclock.attendance.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nineclock.attendance.dto.AttendGroupDTO;
import com.nineclock.attendance.dto.AttendGroupPCExtraConfigDTO;
import com.nineclock.attendance.dto.AttendGroupPartDTO;
import com.nineclock.attendance.enums.AttendEnums;
import com.nineclock.attendance.mapper.AttendGroupMapper;
import com.nineclock.attendance.mapper.AttendGroupPartMapper;
import com.nineclock.attendance.pojo.AttendGroup;
import com.nineclock.attendance.pojo.AttendGroupPart;
import com.nineclock.attendance.service.AttendanceGroupService;
import com.nineclock.common.entity.PageResult;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.threadlocal.CurrentUserHolder;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.common.utils.JsonUtils;
import com.nineclock.system.feign.SysUserFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 黑马程序员
 * @Company http://www.ithiema.com
 * @Version 1.0
 */
@Service
public class AttendanceGroupServiceImpl implements AttendanceGroupService {


    @Autowired
    AttendGroupMapper attendGroupMapper;

    @Autowired
    AttendGroupPartMapper attendGroupPartMapper;


    @Autowired
    SysUserFeign userFeign;
    /**
     * 1. 查询企业是否初次使用， 如果没有查询到考勤组， 说明第一次使用，初始化默认考勤组
     * 2. 分页查询考勤组列表
     * 3. 查询每个考勤组的 关联的员工人数， 组装数据
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public PageResult<AttendGroupDTO> queryAttendGroupPage(Integer page, Integer pageSize) {

        LambdaQueryWrapper<AttendGroup> attendGroupQw = new LambdaQueryWrapper<>();
        attendGroupQw.eq(AttendGroup::getCompanyId, CurrentUserHolder.get().getCompanyId());

        Integer count = attendGroupMapper.selectCount(attendGroupQw);
        if(count == 0){
            //说明初次使用，初始化默认考勤组
            AttendGroup attendGroup = this.buildDefaultAttendGroup();
            
            attendGroupMapper.insert(attendGroup);

            //维护考勤组和 部门/员工 之间的关联关系
            List<Long> ids =
                    userFeign.queryDepartmentIds().getData();
            if(CollectionUtil.isNotEmpty(ids)){
                for (Long departmentId : ids) {
                    AttendGroupPart attendGroupPart = new AttendGroupPart();
                    //设置考勤组的id
                    attendGroupPart.setAttendGroupId(attendGroup.getId());
                    //设置 关联的对象 为部门类型
                    attendGroupPart.setObjectType(AttendEnums.ATTEND_OBJECT_TYPE_DEP.value());
                    //设置关联的对象id
                    attendGroupPart.setObjectId(departmentId);
                    //是否参与打卡
                    attendGroupPart.setAttendType(AttendEnums.ATTEND_TYPE_YES.value());
                    //保存关系到数据库
                    attendGroupPartMapper.insert(attendGroupPart);
                }
            }

        }

        //分页查询考勤组
        LambdaQueryWrapper<AttendGroup> attendGroupPageQw = new LambdaQueryWrapper<>();

        attendGroupPageQw.eq(AttendGroup::getCompanyId, CurrentUserHolder.get().getCompanyId());

        Page<AttendGroup> attendGroupPage = new Page(page, pageSize);;
        //分页查询
        attendGroupPage = attendGroupMapper.selectPage(attendGroupPage, attendGroupPageQw);
        //获取 查询到的考勤组数据
        List<AttendGroup> records = attendGroupPage.getRecords();

        //转换为DTO类型
        List<AttendGroupDTO> attendGroupDTOList = BeanHelper.copyWithCollection(records, AttendGroupDTO.class);

        //统计每个考勤组关联的员工个数
        for (AttendGroupDTO attendGroup : attendGroupDTOList) {
            LambdaQueryWrapper<AttendGroupPart> attendGroupPartQw = new LambdaQueryWrapper<>();
            attendGroupPartQw.eq(AttendGroupPart::getAttendGroupId, attendGroup.getId());
            //查询该考勤组关联的 关系对象
            List<AttendGroupPart> attendGroupPartList = attendGroupPartMapper.selectList(attendGroupPartQw);

            //统计关系对象中 员工的id
            List<Long> userIds = attendGroupPartList.stream().filter(attendGroupPart -> {
                //filter 过滤器， 相当于 if判断， 如果 员工类型 ，返回objectId
                return attendGroupPart.getObjectType() == AttendEnums.ATTEND_OBJECT_TYPE_USER.value();
            }).map(attendGroupPart -> {
                return attendGroupPart.getObjectId();
            }).collect(Collectors.toList());

            //统计关系对象中 部门id
            List<Long> departmentIds = attendGroupPartList.stream().filter(attendGroupPart -> {
                //filter 过滤器， 相当于 if判断， 如果 部门类型 ，返回objectId
                return attendGroupPart.getObjectType() == AttendEnums.ATTEND_OBJECT_TYPE_DEP.value();
            }).map(attendGroupPart -> {
                return attendGroupPart.getObjectId();
            }).collect(Collectors.toList());

            //查询部门下的员工个数
            Integer userCountOfDepartment = userFeign.queryUserCountByDepartmentId(departmentIds).getData();
            //该考勤组对应的员工数量
            Integer number = userIds.size() + userCountOfDepartment;
            //设置该考勤组对应的员工数量
            attendGroup.setMemberNum(number);

        }

        return new PageResult<>(attendGroupPage.getTotal(), attendGroupPage.getPages(), attendGroupDTOList);
    }

    @Override
    public void addAttendGroup(AttendGroupDTO attendGroupDTO) {
        if(attendGroupDTO == null){
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }
        AttendGroup attendGroup = BeanHelper.copyProperties(attendGroupDTO, AttendGroup.class);
        attendGroup.setCompanyId(CurrentUserHolder.get().getCompanyId());
        //设置工作日
        attendGroup.setWorkdays(JsonUtils.toString(attendGroupDTO.getWorkdays()));
        attendGroup.setWorkdays(String.join(",", attendGroupDTO.getWorkdays()));


        //需要打卡的日期
        List<String> punchDate = new ArrayList<>();
        //无需打卡的日期
        List<String> unPunchDate = new ArrayList<>();

        //获取 无需  和需要打卡的日期
        List<AttendGroupPCExtraConfigDTO> extraConfig = attendGroupDTO.getExtraConfig();
        for (AttendGroupPCExtraConfigDTO attendGroupPCExtraConfigDTO : extraConfig) {
            //需要打卡，把日期添加到需要打卡的集合中
            if(attendGroupPCExtraConfigDTO.getRequiredAttend() == 1){
                punchDate.add(attendGroupPCExtraConfigDTO.getSetDate());
            }
            if(attendGroupPCExtraConfigDTO.getRequiredAttend() == 0){
                unPunchDate.add(attendGroupPCExtraConfigDTO.getSetDate());
            }
        }

        attendGroup.setNecessaryTimeList(JsonUtils.toString(punchDate));
        attendGroup.setUnnecessaryTimeList(JsonUtils.toString(unPunchDate));

        attendGroup.setCreateTime(new Date());
        attendGroup.setCreateUserId(CurrentUserHolder.get().getCompanyUserId());

        //新增考勤组
        attendGroupMapper.insert(attendGroup);

        //维护考勤组 与 部门或员工的关系(如果原来有关系，删除， 没有关系，新增)
        //需要考勤的
        List<AttendGroupPartDTO> participates = attendGroupDTO.getParticipates();
        //循环处理需要考勤的人员
        for (AttendGroupPartDTO participate : participates) {
            //删除需要考勤的人员 与 其他考勤组的关系
            LambdaQueryWrapper<AttendGroupPart> attendGroupPartQw = new LambdaQueryWrapper<>();
            attendGroupPartQw.eq(AttendGroupPart::getObjectType, participate.getObjectType());
            attendGroupPartQw.eq(AttendGroupPart::getObjectId, participate.getObjectId());

            attendGroupPartMapper.delete(attendGroupPartQw);

            //维护新的关系

            AttendGroupPart attendGroupPart = new AttendGroupPart();
            attendGroupPart.setAttendGroupId(attendGroup.getId());
            attendGroupPart.setObjectType(participate.getObjectType());
            attendGroupPart.setObjectId(participate.getObjectId());
            attendGroupPart.setAttendType(1);

            attendGroupPartMapper.insert(attendGroupPart);
        }

        //无需考勤的
        List<AttendGroupPartDTO> notParticipates = attendGroupDTO.getNotParticipates();
        for (AttendGroupPartDTO notParticipate : notParticipates) {
            //删除需要考勤的人员 与 其他考勤组的关系
            LambdaQueryWrapper<AttendGroupPart> attendGroupPartQw = new LambdaQueryWrapper<>();
            attendGroupPartQw.eq(AttendGroupPart::getObjectType, notParticipate.getObjectType());
            attendGroupPartQw.eq(AttendGroupPart::getObjectId, notParticipate.getObjectId());

            attendGroupPartMapper.delete(attendGroupPartQw);

            //维护新的关系

            AttendGroupPart attendGroupPart = new AttendGroupPart();
            attendGroupPart.setAttendGroupId(attendGroup.getId());
            attendGroupPart.setObjectType(notParticipate.getObjectType());
            attendGroupPart.setObjectId(notParticipate.getObjectId());
            attendGroupPart.setAttendType(2);

            attendGroupPartMapper.insert(attendGroupPart);
        }
    }

    @Override
    public AttendGroupDTO getAttendGroupByUserId() {
        //查询当前用户的考勤组
        Long companyUserId = CurrentUserHolder.get().getCompanyUserId();

        AttendGroupPart attendGroupPart = this.getAttendGroupPart(companyUserId, AttendEnums.ATTEND_OBJECT_TYPE_USER.value());

        if(attendGroupPart == null){
            //查询该员工所在部门参与了 哪个打卡组
            List<Long> departmentIds = userFeign.queryDepartmentsByUserId(companyUserId).getData();

            if(CollectionUtil.isNotEmpty(departmentIds)){
                for (Long departmentId : departmentIds) {
                    attendGroupPart = this.getAttendGroupPart(departmentId, AttendEnums.ATTEND_OBJECT_TYPE_DEP.value());
                    if(attendGroupPart != null){
                        break;
                    }
                }
            }
        }

        if(attendGroupPart != null){
            //查询考勤组对象
            AttendGroup attendGroup = attendGroupMapper.selectById(attendGroupPart.getAttendGroupId());

            //转换为dto数据
            AttendGroupDTO attendGroupDTO = BeanHelper.copyProperties(attendGroup, AttendGroupDTO.class);
            //1,0,1,0,1,0,0
            String workdays = attendGroup.getWorkdays();
            String[] split = workdays.split(",");
            List<String> workdayList = Arrays.asList(split);

            attendGroupDTO.setWorkdays(workdayList);

            return attendGroupDTO;
        }

        return null;
    }


    public AttendGroupPart getAttendGroupPart(Long companyUserId,Integer objectType ){
        LambdaQueryWrapper<AttendGroupPart> attendGroupPartQw = new LambdaQueryWrapper<>();
        attendGroupPartQw.eq(AttendGroupPart::getObjectId, companyUserId);
        attendGroupPartQw.eq(AttendGroupPart::getObjectType, objectType);

        AttendGroupPart attendGroupPart = attendGroupPartMapper.selectOne(attendGroupPartQw);
        return attendGroupPart;
    }

    private AttendGroup buildDefaultAttendGroup() {
        AttendGroup attendGroup = new AttendGroup();
        attendGroup.setName("默认考勤组");
        attendGroup.setCompanyId(CurrentUserHolder.get().getCompanyId());

        attendGroup.setStartWorkTime("09:00:00");
        attendGroup.setAllowLateMinutes(10);
        attendGroup.setLateMinutes(30);

        attendGroup.setStartNoonRestTime("12:00:00");
        attendGroup.setEndNoonRestTime("14:00:00");

        attendGroup.setOffWorkTime("17:00:00");

        attendGroup.setWorkdays("[1,1,1,1,1,0,0]");
        attendGroup.setAddress("北京市昌平区北七家TBD云集中心");
        attendGroup.setAddressName("昌平校区");

        attendGroup.setLat(new BigDecimal(116.373778));
        attendGroup.setLng(new BigDecimal(40.104674));

        attendGroup.setAddressRange(1000);

        attendGroup.setCreateUserId(CurrentUserHolder.get().getCompanyUserId());
        attendGroup.setCreateTime(new Date());







        return attendGroup;

    }
}
